# 注册和登陆
from . import passport_blue
from flask import request, abort, current_app, make_response, jsonify, session
from info.utils.captcha.captcha import captcha
from info import redis_store, constants, response_code, db
import json, re, random, datetime
from info.libs.yuntongxun.sms import CCP
from info.models import User


@passport_blue.route('/logout', methods=['GET'])
def logout():
    """
        退出登陆
        清理session
    """
    try:
        session.pop('user_id', None)
        session.pop('mobile', None)
        session.pop('nick_name', None)

        # 为了防止管理员误入前台界面后，退出登陆时留下了is_admin标记，所以无论是谁只要退出登陆，都要清理is_admin
        session.pop('is_admin', False)

    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=response_code.RET.DBERR, errmsg='退出登陆失败')

    return jsonify(errno=response_code.RET.OK, errmsg='退出登陆成功')


@passport_blue.route('/login', methods=['POST'])
def login():
    """
        登陆
    1.获取参数（手机号，密码明文）
    2.校验参数（判断参数是否缺少和手机号是否合法）
    3.使用手机号查询用户信息
    4.校验用户密码是否正确
    5.将状态保持信息写入到session，完成登陆
    6.记录最后一次登陆时间
    7.响应登陆结束
    """

    # 1.获取参数（手机号，密码明文）
    json_dict = request.json
    mobile = json_dict.get('mobile')
    password = json_dict.get('password')

    # 2.校验参数（判断参数是否缺少和手机号是否合法）
    if not all([mobile, password]):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='缺少参数')
    if not re.match(r'^1[345678][0-9]{9}$', mobile):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='手机格式不对')

    # 3.使用手机号查询用户信息
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=response_code.RET.DBERR, errmsg='查询用户数据失败')
    if not user:
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='用户名或密码错误')

    # 4.校验用户密码是否正确
    if not user.check_password(password):
        return jsonify(errno=response_code.RET.PWDERR, errmsg='用户名或密码错误')

    # 5.将状态保持信息写入到session，完成登陆
    session['user_id'] = user.id
    session['mobile'] = user.mobile
    session['nick_name'] = user.nick_name

    # 6.记录最后一次登陆时间
    user.last_login = datetime.datetime.now()
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=response_code.RET.DBERR, errmsg='记录最后一次登陆时间失败了')

    # 7.响应登陆结束
    return jsonify(errno=response_code.RET.OK, errmsg='登陆成功喽！')


@passport_blue.route('/register', methods=['POST'])
def register():
    """
    注册
        1.接受参数（手机号 短信验证码 密码明文）
        2.校验参数（判断是否缺少 和 手机号是否合法）
        3.查询服务器的短信验证码
        4.跟客户端传入的短信验证码对比
        5.如果对比成功，就创建user模型 并对属性赋值
        6.将模型数据同步到数据库
        7.保存session，实现状态保持，注册即登陆
        8.响应注册结果
    """

    # 1.接受参数（手机号,短信验证码,密码明文）
    json_dict = request.json
    mobile = json_dict.get('mobile')
    smscode_client = json_dict.get('smscode')
    password = json_dict.get('password')

    # 2.校验参数（判断是否缺少和手机号是否合法）
    if not all([mobile, smscode_client, password]):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='缺少参数')
    if not re.match(r'^1[345678][0-9]{9}$', mobile):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='手机格式不对')

    # 3.查询服务器的短信验证码
    try:
        smscode_server = redis_store.get('SMS:' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=response_code.RET.DBERR, errmsg='短信验证码失败')
    if not smscode_server:
        return jsonify(errno=response_code.RET.NODATA, errmsg='短信验证码不存在')

    # 4.跟客户端传入的短信验证码对比
    if smscode_client != smscode_server:
        return jsonify(errno=response_code.RET.NODATA, errmsg='输入短信验证码有误')

    # 5.如果对比成功，就创建user模型 并对属性赋值
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    # 加密后再储存
    # 方案一：再视图中，直接调用对应的密码加密的算法，加密密码存储到数据库
    # 方案二：在这个视图中，封装一个加密的方法，加密密码存储到数据库
    # 方案三：再模型类中新增一个属性叫password，并加载setter和getter方法，直接完成密码的加密存储
    # psd = user.password = password
    user.password = password  # setter方法

    # 记录最后一次登陆时间
    user.last_login = datetime.datetime.now()

    # 6.将模型数据同步到数据库

    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=response_code.RET.DBERR, errmsg='保存注册数据失败')

    # 7.保存session，实现状态保持，注册即登陆
    session['user_id'] = user.id

    # 8.响应注册结果
    return jsonify(errno=response_code.RET.OK, errmsg='注册成功')


@passport_blue.route('/sms_code', methods=['POST'])
def sms_code():
    # 发送短信
    # 1.接受参数（手机号，图片验证码，uuid）
    # 2.校验参数是否齐全，手机号是否合法
    # 3.查询服务器存储的图片验证码
    # 4.跟客户端传入的图片验证码对比
    # 5.如果对比成功，生成短信验证码，并发送短信
    # 6.存储短信验证码到redis，方便注册时比较
    # 7.响应短信验证码发送的结果

    # 1.接受参数（手机号，图片验证码，uuid）
    json_str = request.data.decode()
    json_dict = json.loads(json_str)
    mobile = json_dict.get('mobile')
    image_code_client = json_dict.get('image_code')
    image_code_id = json_dict.get('image_code_id')

    # 2.校验参数是否齐全，手机号是否合法
    if not all([mobile, image_code_client, image_code_id]):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='缺少参数')
    if not re.match(r'^1[345678][0-9]{9}$', mobile):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='手机格式不对')

    # 3.查询服务器存储的图片验证码
    try:
        image_code_server = redis_store.get('ImageCode:' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=response_code.RET.DBERR, errmsg='查询图片验证码失败')
    if not image_code_server:
        return jsonify(errno=response_code.RET.NODATA, errmsg='图片验证码不存在')

    # 4.跟客户端传入的图片验证码对比.
    print(image_code_server.lower())
    if image_code_server.lower() != image_code_client.lower():
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='输入验证码不对')

    # 5.如果对比成功，生成短信验证码，并发送短信
    # '%06d':如果不够6位 补0
    sms_code = '%06d' % random.randint(0, 999999)
    current_app.logger.debug(sms_code)
    result = CCP().send_template_sms(mobile, [sms_code, 5], 1)
    if result != 0:
        return jsonify(errno=response_code.RET.THIRDERR, errmsg='发送短信验证码失败')

    # 6.存储短信验证码到redis，方便注册时比较
    try:
        redis_store.set('SMS:' + mobile, sms_code, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        return jsonify(errno=response_code.RET.DBERR, errmsg='保存短信验证码失败')

    # 7.响应短信验证码发送的结果
    return jsonify(errno=response_code.RET.OK, errmsg='发送验证码成功')


@passport_blue.route('/image_code', methods=['GET'])
def image_code():
    # 提供图片验证码
    """
        1.接受参数（uuid）
        2.校验参数（判断uuid是否为空）
        3.生成图片验证码
        4.保存图片验证码到redis
        5.修改image的ContentType=‘image/jpg’
        6.相应图片验证码
    """
    # 1.接受参数（uuid）
    imageColdId = request.args.get('imageCodeId')

    # 2.校验参数（判断uuid是否为空）
    if not imageColdId:
        abort(403)

    # 3.生成图片验证码
    name, text, image = captcha.generate_captcha()
    current_app.logger.debug(text)

    # 4.保存图片验证码到redis
    try:
        redis_store.set('ImageCode:' + imageColdId, text, constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        abort(500)

    # 5.修改image的ContentType =‘image / jpg’
    response = make_response(image)
    response.headers['Content-Type'] = 'image/jpg'

    # 6.相应图片验证码
    return response
